using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using LFloatMath.Collision2D;
using LFloatMath.Math;

namespace IQIGame.Onigao.Logic
{
    public class SkillEffective_Impact : SkillEffective
    {
        protected override bool effectiveOne => true;

        protected override ISerializeCustomPOD OnExecute(SkillEffectiveData data, Unit target, SkillEffectiveContext context, int effectiveIndex, out SkillEffectiveResponse startResp)
        {
            startResp = null;
            
            if (data.effectiveConfig.customConfig is SkillEffective_Impact_ConfigData rConfig)
            {
                var rImpactResp = ClassPool<ImpactResponse>.Get();

                // 冲锋，向前检测碰撞，碰到东西就停
                var rAttacker = context.skill.executer;
                var rCollCtrl = rAttacker.battle.playCtrl.collisionCtrl;
                var rCenter = rAttacker.pos;
                var rDir = context.selectParam.aspect.normalized;
                // 这里要验证出界，来修正最远冲撞距离
                var rMapCtrl = rAttacker.battle.playCtrl.mapCtrl;
                Utils.TestRayCircle(rMapCtrl.startPos, rMapCtrl.radius, rAttacker.pos, rDir, out var fMaxDistance);
                var fConfigMaxLength = new LFloat(true, rConfig.maxLength);
                if (fMaxDistance > 0)
                {
                    fMaxDistance = fConfigMaxLength;
                }
                else
                {
                    fMaxDistance = fConfigMaxLength;
                }
                var rList = ListPool<LVector2>.Get();
                // 前方边缘点
                var rMid = rCenter + rDir * rAttacker.radius;
                rList.Add(rMid);
                for (int i = 0; i < rConfig.checkNum; i++)
                {
                    var fRadius = rAttacker.radius * (i + 1) / rConfig.checkNum;
                    // 逆时针方向边缘点
                    var rLeft = rCenter + new LVector2(-rDir.y, rDir.x) * fRadius;
                    // 顺时针方向边缘点
                    var rRight = rCenter + new LVector2(rDir.y, -rDir.x) * fRadius;
                    rList.Add(rLeft);
                    rList.Add(rRight);
                }
                bool bHasCollision = false;
                var nUnit = 0;
                for (int i = 0; i < rList.Count; i++)
                {
                    var rStartPoint = rList[i];
                    if (rCollCtrl.RayCast(new Ray2D(rStartPoint, rDir),
                            out var rHit, out var nHitUnit, fMaxDistance, rAttacker))
                    {
                        bHasCollision = true;
                        fMaxDistance = rHit.distance;
                        nUnit = nHitUnit;
                    }
                }
                ListPool<LVector2>.Put(rList);

                var rNewPos = rCenter + rDir * fMaxDistance;

                rImpactResp.speed = new LFloat(true, rConfig.speed);
                rImpactResp.aspect = rDir;
                rImpactResp.targetPos = rNewPos;

                var rEffectiveResp = ClassPool.Get<SkillEffectiveResponse>();
                rEffectiveResp.effectiveType = data.effectiveConfig.type;
                rEffectiveResp.pod = rImpactResp;
                startResp = rEffectiveResp;

                rAttacker.SetPos(rNewPos, LVector2.zero, null, false);
                if (bHasCollision)
                {
                    var rTargetUnit = rAttacker.battle.playCtrl.unitCtrl.GetUnit(nUnit);
                    var rTargetRelation = (ETargetRelation)rConfig.targetRelation;
                    var rRelation = BattleUtil.CheckRelation(rAttacker, rTargetUnit);
                    if ((rRelation & rTargetRelation) > 0)
                    {
                        rImpactResp.packageResp = SkillEffective_Package.PackageOnExecute(rConfig.actions, rTargetUnit, ref context, effectiveIndex) as SkillEffectivePackageResponse;
                    }

                    return rImpactResp;
                }
            }
            return null;
        }

#if UNITY_EDITOR
        public override string ToString(SkillCustomConfig config)
        {
            return $"冲撞";
        }
#endif
    }
}